From c180e655c186e6cacc56bbdd20bb301f5df2b10b Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Sat, 23 Sep 2006 14:47:00 +0100 Subject: [PATCH] Use GDB 'O' packets for console output if the serial line is shared and GDB is attached. It may be necessary for gdb and the console to share a serial port. This patch utilises the GDB protocol to encode console output. Based on a patch from Tony Breeds Signed-off-by: Keir Fraser --- xen/common/gdbstub.c | 52 ++++++++++++++++++++++++++++++-------- xen/drivers/char/console.c | 36 +++++++++++++++++++++++--- xen/include/xen/console.h | 9 +++++++ xen/include/xen/gdbstub.h | 3 ++- 4 files changed, 85 insertions(+), 15 deletions(-) diff --git a/xen/common/gdbstub.c b/xen/common/gdbstub.c index 8934122925..257547ed19 100644 --- a/xen/common/gdbstub.c +++ b/xen/common/gdbstub.c @@ -357,6 +357,25 @@ gdb_cmd_write_mem(unsigned long addr, unsigned long length, gdb_send_packet(ctx); } +static void +gdbstub_attach(struct gdb_context *ctx) +{ + static void gdbstub_console_puts(const char *str); + if ( ctx->currently_attached ) + return; + ctx->currently_attached = 1; + ctx->console_steal_id = console_steal(ctx->serhnd, gdbstub_console_puts); +} + +static void +gdbstub_detach(struct gdb_context *ctx) +{ + if ( !ctx->currently_attached ) + return; + ctx->currently_attached = 0; + console_giveback(ctx->console_steal_id); +} + /* command dispatcher */ static int process_command(struct cpu_user_regs *regs, struct gdb_context *ctx) @@ -427,7 +446,7 @@ process_command(struct cpu_user_regs *regs, struct gdb_context *ctx) gdb_arch_read_reg(addr, regs, ctx); break; case 'D': - ctx->currently_attached = 0; + gdbstub_detach(ctx); gdb_send_reply("OK", ctx); /* fall through */ case 'k': @@ -444,7 +463,7 @@ process_command(struct cpu_user_regs *regs, struct gdb_context *ctx) ctx->in_buf[1] ) addr = str2ulong(&ctx->in_buf[1], sizeof(unsigned long)); if ( ctx->in_buf[0] != 'D' ) - ctx->currently_attached = 1; + gdbstub_attach(ctx); resume = 1; gdb_arch_resume(regs, addr, type, ctx); break; @@ -459,17 +478,29 @@ process_command(struct cpu_user_regs *regs, struct gdb_context *ctx) static struct gdb_context __gdb_ctx = { - .serhnd = -1, - .currently_attached = 0, - .running = ATOMIC_INIT(1), - .connected = 0, - .signum = 1, - .in_bytes = 0, - .out_offset = 0, - .out_csum = 0, + .serhnd = -1, + .running = ATOMIC_INIT(1), + .signum = 1 }; static struct gdb_context *gdb_ctx = &__gdb_ctx; +static void +gdbstub_console_puts(const char *str) +{ + const char *p; + + gdb_start_packet(gdb_ctx); + gdb_write_to_packet_char('O', gdb_ctx); + + for ( p = str; *p != '\0'; p++ ) + { + gdb_write_to_packet_char(hex2char((*p>>4) & 0x0f), gdb_ctx ); + gdb_write_to_packet_char(hex2char((*p) & 0x0f), gdb_ctx ); + } + + gdb_send_packet(gdb_ctx); +} + /* trap handler: main entry point */ int __trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie) @@ -525,6 +556,7 @@ __trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie) gdb_arch_enter(regs); gdb_ctx->signum = gdb_arch_signal_num(regs, cookie); + /* If gdb is already attached, tell it we've stopped again. */ if ( gdb_ctx->currently_attached ) { diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index 1bba161223..c3e17efe72 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -116,6 +116,34 @@ long read_console_ring(XEN_GUEST_HANDLE(char) str, u32 *pcount, int clear) static char serial_rx_ring[SERIAL_RX_SIZE]; static unsigned int serial_rx_cons, serial_rx_prod; +static void (*serial_steal_fn)(const char *); + +int console_steal(int handle, void (*fn)(const char *)) +{ + if ( (handle == -1) || (handle != sercon_handle) ) + return 0; + + if ( serial_steal_fn == NULL ) + return -EBUSY; + + serial_steal_fn = fn; + return 1; +} + +void console_giveback(int id) +{ + if ( id == 1 ) + serial_steal_fn = NULL; +} + +static void sercon_puts(const char *s) +{ + if ( serial_steal_fn != NULL ) + (*serial_steal_fn)(s); + else + serial_puts(sercon_handle, s); +} + /* CTRL- switches input direction between Xen and DOM0. */ #define SWITCH_CODE (opt_conswitch[0]-'a'+1) static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */ @@ -191,7 +219,7 @@ static long guest_console_write(XEN_GUEST_HANDLE(char) buffer, int count) return -EFAULT; kbuf[kcount] = '\0'; - serial_puts(sercon_handle, kbuf); + sercon_puts(kbuf); for ( kptr = kbuf; *kptr != '\0'; kptr++ ) vga_putchar(*kptr); @@ -257,7 +285,7 @@ static inline void __putstr(const char *str) { int c; - serial_puts(sercon_handle, str); + sercon_puts(str); while ( (c = *str++) != '\0' ) { @@ -448,11 +476,11 @@ static void debugtrace_dump_worker(void) /* Print oldest portion of the ring. */ ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0); - serial_puts(sercon_handle, &debugtrace_buf[debugtrace_prd]); + sercon_puts(&debugtrace_buf[debugtrace_prd]); /* Print youngest portion of the ring. */ debugtrace_buf[debugtrace_prd] = '\0'; - serial_puts(sercon_handle, &debugtrace_buf[0]); + sercon_puts(&debugtrace_buf[0]); memset(debugtrace_buf, '\0', debugtrace_bytes); diff --git a/xen/include/xen/console.h b/xen/include/xen/console.h index d7125a317c..12abd2df51 100644 --- a/xen/include/xen/console.h +++ b/xen/include/xen/console.h @@ -26,4 +26,13 @@ void console_force_lock(void); void console_start_sync(void); void console_end_sync(void); +/* + * Steal output from the console. Returns +ve identifier, else -ve error. + * Takes the handle of the serial line to steal, and steal callback function. + */ +int console_steal(int handle, void (*fn)(const char *)); + +/* Give back stolen console. Takes the identifier returned by console_steal. */ +void console_giveback(int id); + #endif /* __CONSOLE_H__ */ diff --git a/xen/include/xen/gdbstub.h b/xen/include/xen/gdbstub.h index f851f6193d..cf6e7e547c 100644 --- a/xen/include/xen/gdbstub.h +++ b/xen/include/xen/gdbstub.h @@ -33,7 +33,8 @@ char str2hex(const char *str); unsigned long str2ulong(const char *str, unsigned long bytes); struct gdb_context { - int serhnd; + int serhnd; /* handle on our serial line */ + int console_steal_id; /* handle on stolen console */ int currently_attached:1; atomic_t running; unsigned long connected; -- 2.30.2